<?php

defined('BASEPATH') or die('非法请求');

/**
 * 权限控制类
 * @author  Karson
 * @name    auth.php
 * @since   2013-7-24 22:38:50
 */
class Auth {

    var $config, $db;
    var $user_id = 0;
    var $username = '';
    var $lastsessionid = '';
    var $fields = array('user_id' => 0, 'username' => '游客', 'logined' => 0, 'id' => 0, 'gender' => '', 'location' => '', 'url' => '', 'signature' => '', 'active' => 0, 'face30' => '/res/images/common/face30.gif', 'face50' => '/res/images/common/face50.gif', 'face160' => '/res/images/common/face160.gif', 'sign' => '');
    var $role_id = 0;
    var $role_name = '';
    var $role_rank = 0;
    var $role_permission = array();
    var $error = '';

    function __construct() {
        $framework = &get_instance('controller');
        $this->config = $framework->config;
        $this->db = $framework->db;
        $this->cache = $framework->cache;
        $this->cookie = $framework->cookie;
        //初始化判断，用于填充user数组
        $this->is_login();
    }

    /**
     * 获取全部角色信息
     * @return array
     */
    function get_role_data() {
        $role_data = $this->cache->get('role_data');
        if (!$role_data) {
            $role_data = $this->db->simple("SELECT * FROM {pre}role");
            $this->cache->set('role_data', $role_data);
        }
        return $role_data;
    }

    /**
     * 写入所有角色数据缓存
     */
    function set_role_data() {
        $role_data = $this->db->simple("SELECT * FROM {pre}role");
        $this->cache->set('role_data', $role_data);
    }

    /**
     * 获取指定角色的权限数据
     * @param int $role_id 角色ID
     * @param bool $unserialize 是否需要反序列化
     * @return mixed
     */
    function get_permission($role_id = 0, $unserialize = true) {
        $role_id = intval($role_id);
        $role_data = $this->get_role_data();
        if (!is_array($role_data))
            return false;
        foreach ($role_data as $key => $value) {
            if (intval($value['id']) === $role_id) {
                $permission = $unserialize ? unserialize($value['permission']) : $value['permission'];
                return $permission;
            }
        }
        return false;
    }

    /**
     * 修改指定角色的权限
     * @param int $role_id 角色ID
     * @param mixed $permission 权限数据
     * @param bool $serialize 是否序列化数据
     * @return mixed 成功返回影响的数据
     */
    function set_permission($role_id, $permission, $serialize = true) {
        $value['permission'] = $serialize ? serialize($permission) : $permission;
        $row = $this->db->one("SELECT * FROM {pre}role WHERE id={$role_id}");
        if (is_array($row)) {
            $value['modifytime'] = time();
            $this->db->update("{pre}role", $value, array("id" => $role_id));
            $this->set_role_data();
            return true;
        } else {
            return false;
        }
    }

    /**
     * 创建和修改角色信息
     * @param string $name 角色名称
     * @param mixed $permission 角色权限
     * @param bool $overwrite 是否覆盖已经存在的角色
     */
    function set_role($name, $permission = array(), $overwrite = true) {
        $value = array('name' => $name, 'permission' => serialize($permission));
        $row = $this->db->one("SELECT * FROM {pre}role WHERE name='{$name}'");
        if (is_array($row)) {
            if ($overwrite) {
                $value['modifytime'] = time();
                $this->db->update("{pre}role", $value, "name='{$name}'");
            } else {
                return false;
            }
        } else {
            $value['createtime'] = time();
            $this->db->insert("{pre}role", $value);
        }
        $this->set_role_data();
        return true;
    }

    /**
     * 获取指定角色的数据
     * @param int $role_id 角色ID
     * @return mixed
     */
    function get_role($role_id) {
        $role_id = intval($role_id);
        $role_data = $this->get_role_data();
        if (!is_array($role_data))
            return false;
        foreach ($role_data as $key => $value) {
            if (intval($value['id']) === $role_id) {
                $value['permission'] = unserialize($value['permission']);
                return $value;
            }
        }
        return false;
    }

    /**
     * 删除角色信息
     * @param int $role_id 角色ID
     * @return bool 删除成功与否
     */
    function delete_role($role_id) {
        if ($this->db->simple("DELETE FROM {pre}role WHERE id = {$role_id}")) {
            $this->set_role_data();
            return true;
        } else {
            return false;
        }
    }

    /**
     * 注册一个会员
     * @param string $username 用户名
     * @param string $password 密码
     * @param string $email 电子邮件
     * @param string $id ID 可选
     * @return fixed
     */
    function register($username, $password, $email) {
        $time = time();
        $ip = get_ip();
        //$state = $this->config['email_confirm'] ? 0 : 1;
        $referer = $this->cookie->get('referer');
        $data = array('username' => $username, 'nickname' => $username, 'password' => md5s($password), 'role_id' => 10, 'face' => '', 'email' => $email, 'state' => 1);
        $user_id = $this->db->insert("{pre}user", $data);
        if ($user_id) {
            $extension = array(
                'user_id' => $user_id,
                'jointime' => $time, 'joinip' => $ip, 'logintime' => $time, 'loginip' => $ip, 'referer' => $referer
            );
            $count = array(
                'user_id' => $user_id, 'successions' => 1, 'logins' => 1
            );
            $this->db->insert("{pre}user_extension", $extension, true);
            $this->db->insert("{pre}user_count", $count, true);
            init_default_category($user_id);
        }
        return $user_id;
    }

    /**
     * 普通登录
     * @param string $username 用户名
     * @param string $password 密码，未加密
     * @param int $keeptime COOKIE记录时长
     * @return bool
     */
    function login($username, $password, $keeptime = 0) {
        $username = mysql_real_escape_string($username);
        $password = md5s(mysql_real_escape_string($password));
        $keeptime = intval($keeptime);
        return $this->_login($username, $password, $keeptime);
    }

    /**
     * 设置登录访问
     * @param string $username 用户名
     * @param string $password 密码
     * @param int $keeptime 保持时间
     * @return boolean
     */
    function _login($username, $password, $keeptime) {
        $urow = $this->db->one("SELECT id FROM {pre}user WHERE username='{$username}'");
        if (is_array($urow)) {
            $row = $this->db->one("SELECT * FROM {pre}user WHERE password='{$password}' AND id='{$urow['id']}'");
            if (!is_array($row)) {
                $this->error = '用户名或密码出错';
                return false;
            }
            if (!$row['state']) {
                $this->error = '账户被锁定，暂时不能登录';
                return false;
            }
            if (!isset($_SESSION))
                session_start();
            $sessionid = session_id();
            $this->cookie->set('user_id', $row['id'], $keeptime);
            $this->cookie->set('username', $row['username'], 86400 * 365);
            //加密安全字符
            $this->cookie->set('safecode', md5($row['id'] . $row['username'] . $row['password']), $keeptime);
            $this->cookie->set('lastsessionid', $sessionid, $keeptime);

            $role = $this->get_role($row['role_id']);
            $this->user_id = $row['id'];
            $this->username = $row['username'];
            $this->role_id = $role['id'];
            $this->role_name = $role['name'];
            $this->role_rank = $role['rank'];
            $this->role_permission = $role['permission'];
            $this->lastsessionid = $row['lastsessionid'];
            $row['face160'] = get_user_face($row['id'], $row['face'], 160);
            $row['face50'] = get_user_face($row['id'], $row['face'], 50);
            $row['face30'] = get_user_face($row['id'], $row['face'], 30);
            $row['face_pos'] = $row['face'];
            $row['face'] = $row['face50'];
            $this->fields = $row;
            //附加其它信息
            $this->fields['sign'] = md5("#ji#zhang#jia" . $row['id']);
            $this->fields['logined'] = 1;
            $this->fields['newmsg'] = 0; //首次不判断
            $this->fields['user_id'] = $row['id'];
            $this->fields['role_name'] = $role['name'];
            $this->fields['role_rank'] = $role['rank'];
            $this->fields['role_permission'] = $role['permission'];
            $time = time();
            $ip = get_ip();
            if (!$this->check_succession()) {
                //会员扩展信息
                $this->db->query("UPDATE {pre}user_extension SET lastlogintime=logintime,lastloginip=loginip,logintime={$time},loginip='{$ip}' WHERE user_id='{$this->fields['id']}'");
            }
            $this->db->query("UPDATE {pre}user SET lastsessionid='{$sessionid}' WHERE id='{$this->fields['id']}'");
            $this->error = '';
            return true;
        } else {
            $this->error = '用户名或密码出错';
            return false;
        }
    }

    /**
     * 判断首次登录及是否连续登录,并返回连续登录天数
     * @return int
     */
    function check_succession() {
        $time = time();
        $ip = get_ip();
        //记录每天首次登录,及连续登录次数
        if (get_unixtime('day') > $this->fields['logintime']) {

            //判断是否连续登录
            if ($this->fields['logintime'] > get_unixtime('day', -1)) {
                $successions = $this->fields['successions'] + 1;
                $signins = "";
            } else {
                $successions = 1;
                $signins = ",signins='0'";
            }
            //连续登录和总登录,今天在线和总在线时长
            $this->db->query("UPDATE {pre}user_count SET successions='{$successions}',logins=logins+1{$signins} WHERE user_id='{$this->fields['id']}'");
            //会员扩展信息
            $this->db->query("UPDATE {pre}user_extension SET lastlogintime=logintime,lastloginip=loginip,logintime={$time},loginip='{$ip}' WHERE user_id='{$this->fields['id']}'");
            $this->fields = array_merge($this->fields, array('successions' => $successions, 'logintime' => $time, 'loginip' => $ip));
            return $successions;
        } else {
            return 0;
        }
    }

    /**
     * 使用加密后的用户名密码快速登录
     * @param string $username
     * @param string $password
     * @param int $keeptime
     * @return boolean
     */
    function fast_login($username, $password, $keeptime = 0) {
        return $this->_login($username, $password, $keeptime);
    }

    /**
     * 注销登录退出
     * @return bool
     */
    function logout() {
        $this->user_id = 0;
        $this->username = '';
        $this->lastsessionid = '';
        $this->fields = null;
        $this->cookie->clear('user_id');
        //$this->cookie->clear('username');
        $this->cookie->clear('safecode');
        $this->cookie->clear('lastsessionid');
        $this->cookie->clear('renren_logined');
        $this->cookie->clear('weibo_logined');
        $this->cookie->clear('qq_logined');
        $_SESSION['qq_token'] = '';
        $_SESSION['weibo_token'] = '';
        $_SESSION['renren_token'] = '';
        return true;
    }

    /**
     * 判断用户是否登录
     * @return bool
     */
    function is_login() {
        $this->user_id = intval($this->cookie->get('user_id'));
        if ($this->user_id > 0) {
            if ($this->fields['logined'] == 1)
                return true;
            if ($this->error)
                return false;
            $row = $this->db->one("SELECT * FROM {pre}user u
                LEFT JOIN {pre}user_count uc ON u.id = uc.user_id
                LEFT JOIN {pre}user_extension ue ON u.id = ue.user_id
                WHERE u.id='{$this->user_id}' AND u.state>0");
            if (!is_array($row)) {
                $this->error = '用户不存在或正在审核';
                return false;
            }

            if ($this->cookie->get('lastsessionid') != $row['lastsessionid'] && $row['username'] != 'test') {
                $this->logout();
                $this->error = '该用户已经在另外一点登录';
                return false;
            }
            $safecode = md5($row['id'] . $row['username'] . $row['password']);
            if ($safecode != $this->cookie->get('safecode')) {
                $this->error = '用户名或密码已经修改';
                return false;
            }
            //获取角色信息及权限
            $role = $this->get_role($row['role_id']);
            $this->username = $row['username'];
            $this->role_id = $role['id'];
            $this->role_name = $role['name'];
            $this->role_rank = $role['rank'];
            $this->role_permission = $role['permission'];
            $this->lastsessionid = $row['lastsessionid'];
            $row['face160'] = get_user_face($row['id'], $row['face'], 160);
            $row['face50'] = get_user_face($row['id'], $row['face'], 50);
            $row['face30'] = get_user_face($row['id'], $row['face'], 30);
            $row['face_pos'] = $row['face'];
            $row['face'] = $row['face50'];
            $this->fields = $row;
            //附加其它信息
            $this->fields['sign'] = md5("#fan#quan#wang" . $row['id']);
            $this->fields['logined'] = 1;
            $this->fields['user_id'] = $row['id'];
            $this->fields['role_name'] = $role['name'];
            $this->fields['role_rank'] = $role['rank'];
            $this->fields['role_permission'] = $role['permission'];
            $this->error = '';
            return true;
        } else {
            $this->error = '您未登录，请登录后再进行操作';
            return false;
        }
    }

    /**
     * 判断是否具有访问uri的权限
     * @param string $uri 指定的uri，默认为空，为空时取当前的控制器和方法
     * @return bool
     */
    function check_uri_permission($uri = '') {
        if (!$this->is_login())
            return false;
        if ($uri == '')
            $uri = current_action();
        $permission = $this->role_permission;
        return is_array($permission) && isset($permission['uri']) && in_array($uri, $permission['uri']) ? true : false;
    }

    /**
     * 获取指定用户的信息
     * @param int $user_id 用户ID
     * @return mixed 成功返回数组信息
     */
    function get_user_data($user_id = null) {
        if (is_null($user_id))
            return null;
        $row = $this->db->one("SELECT * FROM {pre}user WHERE id={$user_id}");
        if (!is_array($row))
            return null;
        unset($row['password']);
        $role = $this->get_role($row['role_id']);
        $row['role_name'] = $role['name'];
        $row['role_permission'] = $role['permission'];
        return $row;
    }

    /**
     * 判断当前浏览者权限
     * @param string $catalog 栏目名称
     * @param string $action 操作权限
     * @return bool
     */
    function check_level($rank = 1, $catalog = null, $action = null) {
        //未登录直接返回false
        if (!$this->is_login())
            return false;
        //判断是否拥有该权限等级
        if ($this->role_rank == 100)
            return true;
        if ($this->role_rank < $rank)
            return false;

        if (is_null($catalog) && is_null($action))
            return true;
        if (is_array($this->role_permission)) {
            //判断允许URI
            $nowurl = $_SERVER['REQUEST_URI'];
            if (isset($this->role_permission['allow_uri']) && count($this->role_permission['allow_uri']) > 0) {
                foreach ($this->role_permission['allow_uri'] as $key => $value) {
                    $value = trim($value);
                    if ($value == '')
                        continue;
                    $urllen = strlen($value);
                    if (substr($nowurl, 0, $urllen) == $value)
                        return true;
                }
            }
            //判断拒绝URI
            if (isset($this->role_permission['deny_uri']) && count($this->role_permission['deny_uri']) > 0) {
                foreach ($this->role_permission['deny_uri'] as $key => $value) {
                    $value = trim($value);
                    if ($value == '')
                        continue;
                    $urllen = strlen($value);
                    if (substr($nowurl, 0, $urllen) == $value)
                        return false;
                }
            }
            //判断指定栏目的权限
            if (!is_null($catalog) && !is_null($action)) {
                if (isset($this->role_permission['admin'][$catalog]) && is_array($this->role_permission['admin'][$catalog]) && in_array($action, $this->role_permission['admin'][$catalog]))
                    return true;
            }else if (!is_null($catalog)) {
                if (in_array($catalog, $this->role_permission['admin']))
                    return true;
            }
            return false;
        }else {
            return false;
        }
    }

}